﻿/// <reference path="jquery.js" />
/// <reference path="res.js" />
'use strict'
//#region Cookie操作方法
jQuery.Cookie = function (name, value, options) {
    /// <summary>
    /// Cookie管理相关方法
    /// </summary>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <param name="options">{expires:以分钟为单位的失效时限，默认随会话，path:有效路径，默认根目录，domain:域名，http:仅限http协议读取,secure:安全性}</param>
    /// <returns type=""></returns>
    if (typeof value != 'undefined') {
        // name and value given, set cookie 
        options = options || { path: "/" };
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        else if (typeof value == 'string') {
            //value = JSON.stringify(value);
        }
        else {
            value = JSON.stringify(value);
        }

        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString())) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + options.expires * 60 * 1000);
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString();
        }

        var path = options.path ? '; path=' + options.path : '';
        var domain = options.domain ? '; domain=' + options.domain : '';
        var secure = options.secure ? '; secure' : '';
        var http = options.http ? ';httponly' : '';
        document.cookie = [name, '=', escape(value), expires, path, domain, secure, http].join('');

    } else {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                if (cookie.substring(0, name.length + 1) == name + '=') {
                    cookieValue = cookie.substring(name.length + 1);
                    break;
                }
            }
        }
        try {
            return JSON.parse(unescape(cookieValue));
        } catch (ex) {
            return unescape(cookieValue);
        }
    }
};
//#endregion

function getUrlParam(name) {
    /// <summary>
    /// 从当前页面路径中获取指定名称的参数项
    /// </summary>
    /// <param name="name"></param>


    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)",'i'); //构造一个含有目标参数的正则表达式对象
    var r = window.location.search.substr(1).match(reg); //匹配目标参数
    if (r != null) {
        return unescape(decodeURI(r[2]));
    } else {
        return null;
    }; //返回参数值
};

function setUrlParam(url, name, value) {
    var newUrl = "";
    var splitIndex = url.indexOf("?") + 1;
    var paramStr = url.substr(splitIndex, url.length);

    newUrl = url.substr(0, splitIndex);

    // - if exist , replace
    var arr = paramStr.split('&');
    for (var i = 0; i < arr.length; i++) {
        var kv = arr[i].split('=');
        if (kv[0] == name) {
            newUrl += kv[0] + "=" + value;
        } else {
            if (kv[1] != undefined) {
                newUrl += kv[0] + "=" + kv[1];
            }
        }
        if (i != arr.length - 1) {
            newUrl += "&";
        }
    }

    // - if new, add
    if (newUrl.indexOf(name) < 0) {
        newUrl += splitIndex == 0 ? "?" + name + "=" + value : "&" + name + "=" + value;
    }
    url = newUrl;
    return newUrl;
};

//#region 通用辅助工具
var ObjHelper = {
    IsEmpty: function IsEmpty(_obj) {
        /// <summary>
        /// 判定一个对象是否为空
        /// </summary>
        /// <param name="_obj">字符串、DOM、数组、JQuery对象</param>
        if (_obj == undefined || _obj == null) {
            return true;
        } else if (typeof _obj == "string") {
            return $.trim(_obj).length == 0;
        } else if (Array.isArray(_obj)) {
            return _obj.length == 0;
        } else if (_obj instanceof jQuery) {
            return _obj.length == 0;
        } else {
            return false;
        }
    },

    IsElement: function IsElement(_obj) {
        /// <summary>
        /// 判断目标对象是否为一个DOM元素或包含DOM元素的JQuery对象
        /// </summary>
        /// <param name="_obj"></param>
        /// <returns type=""></returns>
        if (ObjHelper.IsEmpty(_obj)) {
            return false;
        } else if (_obj.nodeType) {
            return _obj.nodeType === 1 || _obj.nodeType === 11;
        } else if (_obj instanceof jQuery) {
            return _obj.length > 0 && _obj[0].nodeType && _obj[0].nodeType === 1;
        } else {
            return false;
        }
    },

    IsFunc: function IsFunc(_fn) {
        /// <summary>
        /// 判断目标是否为一个函数方法
        /// </summary>
        /// <param name="_fn">目标函数</param>
        /// <returns type=""></returns>
        if (!_fn) {
            return false;
        } else {
            return typeof _fn === "function";
        }
    }
};

//货币符号枚举
var CurrencyEnum = {
    CNY: '￥'
    , USD: '$'
};

//确保浏览器控制台可用
if (!window.console) {
    console = {
        log: function () { },
        error: function () { }
    }
}
else if (!console.error) {
    console.error = function () {

    }
}
else if (!console.log) {
    console.log = function () {

    }
}
else { }

//提供默认简单信息交互方法
window.info = window.info || function (ttl, cnt) { alert("INFO:" + cnt); };
window.error = window.error || function (ttl, err) { alert("ERROR:" + err); };
window.success = window.success || function (ttl, msg) { alert("SUCCESS:" + msg); };
//#endregion

//#region 为原生的DOM元素和JQ对象添加统一的辅助方法
HTMLElement.prototype.vl = function (_newValue) {
    /// <summary>
    /// 获取或设置一个DOM元素的值（根据元素类型text或html）
    /// </summary>
    /// <param name="_newValue" type="type"></param>
    /// <returns type=""></returns>
    if (!ObjHelper.IsEmpty(_newValue)) {
        $(this).vl(_newValue);
        return this;
    } else {
        return $(this).vl();
    }
};

HTMLElement.prototype.ID = function (_newId) {
    /// <summary>
    /// 获取或设置一个DOM元素的ID属性
    /// </summary>
    /// <param name="_newId" type="type"></param>
    /// <returns type=""></returns>
    if (ObjHelper.IsEmpty(_newId)) {
        return $(this).ID();
    } else {
        $(this).ID(_newId);
        return this;
    }
};

HTMLElement.prototype.attr = function (_key, _value) {
    /// <summary>
    /// 获取或设置一个DOM元素的attr属性
    /// </summary>
    /// <param name="_key" type="type"></param>
    /// <param name="_value" type="type"></param>
    /// <returns type=""></returns>
    if (ObjHelper.IsEmpty(_value)) {
        return $(this).attr(_key);
    } else {
        $(this).attr(_key, _value);
        return this;
    }
};

HTMLElement.prototype.disable = function (tip) {
    /// <summary>
    /// 使一个DOM元素处于不可交互状态
    /// </summary>
    /// <param name="_style" type="type"></param>
    /// <returns type=""></returns>
    this.setAttribute("disabled", "disabled");
    var cntEditble = this.getAttribute("contentEditble");
    if (cntEditble === true) {
        this.setAttribute("contentEditble", false);
    };
    this.classList.add("disabled");
    if (tip) {
        this.vl(tip);
    }
    return this;
};

HTMLElement.prototype.enable = function (tip) {
    /// <summary>
    /// 是一个DOM元素处于可交互状态
    /// </summary>
    /// <param name="_style" type="type"></param>
    /// <returns type=""></returns>

    this.removeAttribute("disabled");

    var cntEditble = this.getAttribute("contentEditble");
    if (cntEditble === false) {
        this.setAttribute("contentEditble", true);
    };
    this.classList.remove("disabled");
    if (tip) {
        this.vl(tip);
    }
    return this;
};

HTMLElement.prototype.dispose = function () {
    console.log("html dispose");
    delete this;
};

if (!HTMLElement.prototype.remove) {
    HTMLElement.prototype.remove = function () { console.log("remove", this); };
}

//针对JQuery选择DOM元素后的扩展操作功能
(function ($) {
    $.fn.extend({
        "ID": function ID(_newID) {
            /// <summary>
            /// 为JQuery对象提供与LiberUI控件一致的获取ID属性的方法
            /// </summary>
            /// <param name="_newID"></param>
            if (ObjHelper.IsEmpty(_newID)) {
                var cid = $(this).attr('id');
                if (!cid) {
                    cid = 'id' + Math.random().toString().replace('.', '');
                    $(this).attr('id', cid);
                }
                return cid;
            } else {
                $(this).attr('id', _newID);
                return $(this);
            }
        },

        "dispose": function dispose() {
            /// <summary>
            /// 为JQuery对象提供与LiberUI控件一致的销毁自身的方法
            /// </summary>
            $.each(this, function () {
                $(this).remove('', false);
                delete this;
            });
        },

        "dom": function dom(_elm) {
            if (ObjHelper.IsElement(_elm)) {
                $(this).appendTo(_elm);
                return this;
            } else {
                return $(this);
            }
        },
        "mask": function mask(_cnt, _delay, _fixHeight, _fnOnClick) {
            /// <summary>
            /// 创建一个简单的遮罩层覆盖在指定元素之上
            /// </summary>
            var elm = $(this);
            if (elm.length == 0) {
                return;
            }
            var m = $("<div class='MaskLayer'></div>");

            m[0].addEventListener("click", function (ev) {
                _fnOnClick && _fnOnClick.call(this, ev);
                ev.stopPropagation();
                return false;
            });
            m[0].addEventListener("mousewheel", function (ev) { ev.preventDefault(); ev.stopPropagation(); return false }, { passive: false });
            window.maskIndx = window.maskIndx ? window.maskIndx + 1 : 1;

            if (elm.is("body")) {
                var sty = {
                    "z-index": 10 * window.maskIndx,
                    "height": window.document.documentElement.clientHeight,
                }
                m.css(sty);
                m.prependTo(elm);
            }
            else {
                m.insertAfter(elm);
            }

            m.width(elm.width(true));
            if (_fixHeight) {
                var h = elm.innerHeight();
                if (h == 0) {
                    h = elm[0].scrollHeight;
                }
                m.height(h);
            }
            LayoutHelper.PosToParent(elm, m, "Cover");

            if (ObjHelper.IsElement(_cnt)) {
                _cnt.appendTo(m);
                setTimeout(function (c) {
                    c.find(':enabled').eq(0).focus().select();
                }, 300, _cnt);
                _cnt[0].addEventListener('click', function (ev) {
                    ev.stopPropagation();
                    return false;
                });
                LayoutHelper.Layout2Parent(_cnt, "AllCenter", null, true);
            }
            else {
                m.vl(_cnt);
            }

            var d = parseInt(_delay);
            if (d) {
                var id = m.ID();
                setTimeout(function () { $("#" + id).remove(); }, d * 1000);
            }

            return m;
        },

        "unmask": function unmask(ani) {
            /// <summary>
            /// 移除通过Mask方法创建的遮罩层
            /// </summary>
            /// <param name="noani" type="boolean">是否启用渐隐动画</param>
            /// <returns type=""></returns>
            var mid = $(this).attr("maskid");
            if (mid) {
                if (!ani) {
                    $("#" + mid).remove();
                }
                else {
                    $("#" + mid).fadeOut(1000, function () {
                        this.remove();
                    });
                }
                $(this).removeAttr("maskid");
            }
            else if (!ani) {
                $(this).children(".MaskLayer").remove();
                $(this).siblings(".MaskLayer").remove();
            }
            else {
                $(this).children(".MaskLayer").fadeOut(1000, function () { this.remove(); });
                $(this).siblings(".MaskLayer").fadeOut(1000, function () { this.remove(); });
            }
            window.maskIndx = window.maskIndx ? window.maskIndx - 1 : 1;
            return this;
        },

        "disable": function disable(tip) {
            this.each(function () {
                this.disable();
                if (tip) {
                    this.vl(tip);
                }
            });

            return this;
        },

        "enable": function enable(tip) {
            this.each(function () {
                this.enable(tip);
            });

            return this;
        },

        "vl": function vl(_newValue) {
            var elm = $(this);
            if (_newValue == undefined) {
                if (elm.is("input") || elm.is("textarea")) {
                    return elm.val();
                } else {
                    return elm.html();
                }
            } else {
                if (elm.is("input") || elm.is("textarea")) {
                    elm.val(_newValue);
                } else if (this.nodeType === 3 || this.nodeType === 8 || this.nodeType === 2) {
                    elm.text(_newValue);
                } else {
                    elm.html(_newValue);
                }
                return elm;
            }
        },

        "wait": function wait(_msg, _displayCnt, _loadingImg) {
            /// <summary>
            /// 指定一个元素处于等待状态，并隐藏原有的内容
            /// </summary>
            /// <param name="_msg" type="String Dom">提示文字或元素</param>
            /// <param name="_displayCnt" type="Bool">是否保留原有的内容[默认隐藏]</param>
            /// <param name="_loadingImg" type="Bool">是否使用Gif动画</param>
            /// <returns type=""></returns>
            $(this).each(function () {
                var elm = $(this);
                var wtr = $(this).children(".WaitingWraper");
                if (wtr.length > 0) {
                    wtr.html(_msg);
                }
                else {
                    elm.addClass("Waiting");
                    var h = null;
                    if (!elm[0].style.height) {
                        h = elm.height();
                    };

                    wtr = $("<button class='WaitingWraper'>");
                    if (_loadingImg) {
                        wtr.addClass("withAni");
                    }
                    if (_displayCnt) {
                        wtr.addClass("withCnt");
                    }

                    if (!elm[0].style.height && h) {
                        elm.css("height", h).attr("no-height", "flag");
                    }
                    wtr.prependTo(this).append(_msg).animate({ height: '100%' });

                    wtr.click(function (ev) {
                        ev.preventDefault();
                        ev.stopPropagation();
                        return false;
                    });
                }
            });
            return this;
        },

        "waitEnd": function waitEnd() {
            $(this).each(function () {
                var elm = $(this);

                elm.children(".WaitingWraper").animate({ height: 0, opacity: 0 }, 300, "linear", function (ev) {
                    var nh = elm.attr("no-height");
                    if (nh) {
                        elm.removeClass("Waiting");
                        elm.removeAttr("no-height");
                        elm[0].style.height = null;
                    }
                    this.remove();
                });
            });
            return this;
        },

        "process": function process(ttl, pcr) {
            /// <summary>
            /// 指定一个元素处于执行状态，并隐藏原有的内容
            /// </summary>
            /// <param name="_msg" type="String Dom">提示文字或元素</param>
            /// <param name="_displayCnt" type="Bool">是否保留原有的内容[默认隐藏]</param>
            /// <param name="_loadingImg" type="Bool">是否使用Gif动画</param>
            /// <returns type=""></returns>
            $(this).each(function () {
                var elm = $(this);
                var wtr = $(this).children(".WaitingWraper");
                if (wtr.length == 0) {
                    //初始化进度条内容
                    elm.addClass("Waiting");
                    var h = null;
                    if (!elm[0].style.height) {
                        h = elm.height();
                    }

                    wtr = $("<button class='WaitingWraper withCnt' style='height:100%'><div class='process-bar'></div><span class='process-ttl'>" + ttl.toString() + "</span></button>");

                    if (h) {
                        elm.css("height", h).attr("no-height", "flag");
                    }
                    wtr.prependTo(this);

                    wtr.click(function (ev) {
                        ev.preventDefault();
                        ev.stopPropagation();
                        return false;
                    });
                }

                //更新进度条
                if (!pcr || window.isNaN(pcr) || window.isNaN(parseFloat(pcr))) {
                }
                else {
                    if (pcr > 100) {
                        pcr = "100%";
                    }
                    else if (pcr > 1) {
                        pcr = pcr + "%";
                    }
                    else {
                        pcr = pcr.formatPercent(0);
                    }
                    wtr.children(".process-bar").css("width", pcr);
                }
                wtr.children(".process-ttl").text(ttl);

            });
            return this;
        },

        "processEnd": function processEnd() {
            $(this).each(function () {
                var elm = $(this);

                elm.children(".WaitingWraper").animate({ height: 0, opacity: 0 }, 300, "linear", function (ev) {
                    var nh = elm.attr("no-height");
                    if (nh) {
                        elm.removeClass("Waiting");
                        elm.removeAttr("no-height");
                        elm[0].style.height = null;
                    }
                    this.remove();
                });
            });
            return this;
        },

        "CheckAll": function (ruls) {
            if (this.data("checker")) {
                return this.data("checker").CheckAll(ruls);
            } else { return true; };
        }
    });
})(jQuery);

//#endregion

//#region 布局帮助类方法
var LayoutHelper = {
    Layout2Parent: function Layout2Parent(_targetDOM, _mode, _offset, _absolute) {
        /// <summary>
        /// 将目标元素按指定方式定位到相对其父元素的位置
        /// </summary>
        /// <param name="_targetDOM"></param>
        /// <param name="_mode">定位模式[YCenter,XCenter,AllCenter,Cover]</param>
        /// <param name="_offset">偏移[top,bottom,left,right]</param>
        /// <param name="_absolute">是否使用绝对定位(正常情况下没有区别)</param>
        var tgt = $(_targetDOM);
        var isAbsolute = false;
        if (_absolute === true) {
            isAbsolute = true;
            tgt.css("position", "absolute");
        }
        var p = tgt.parent().eq(0);
        var off = $.extend({ top: 0, bottom: 0, left: 0, right: 0 }, _offset);
        var h = tgt.outerHeight(true);
        if (h == 0) {
            h = tgt[0].scrollHeight;
        }
        var w = tgt.outerWidth(true);
        var ph = p.height();
        var pw = p.width();

        switch (_mode) {
            case "YCenter":
                tgt.css("top", (ph - h) / 2 + off.top - off.bottom + "px");
                break;
            case "XCenter":
                //tgt.css("left", ((pw - w)/2 + off.left - off.right)+"px");
                break;
            case "AllCenter":
                if (tgt.css("position") !== 'absolute' && tgt.css("position") !== 'fixed') {
                    //非绝对定位
                    var style = {
                        position: 'relative',
                        top: (ph - h) / 2 + off.top - off.bottom + 'px',
                        margin: '0 auto'
                    }
                    tgt.css(style);
                }
                else {
                    var style = {
                        left: ((pw - w) / 2 + off.left - off.right) / pw * 100 + '%',
                        top: Math.abs(((ph - h) / 2 + off.top - off.top)) / ph * 100 + '%'
                    }
                    tgt.css(style);
                }
                break;
            case "Bottom":
                tgt.css("top", 0 - ph).css("left", w - pw);
                break;
            default:
                tgt.offset(off);
                break;
        }
        p = null;
        off = null;
    },

    Layout2Wnd: function Layout2Wnd(_targetDOM, _mode, _offset) {
        /// <summary>
        /// 将目标元素按指定方式定位到当前窗口的相对位置
        /// </summary>
        /// <param name="_targetDOM"></param>
        /// <param name="_mode">定位模式[YCenter,XCenter,AllCenter,Cover]</param>
        /// <param name="_offset">偏移[top,bottom,left,right]</param>
        /// <param name="_absolute">是否使用绝对定位(正常情况下没有区别)</param>
        var tgt = $(_targetDOM);
        tgt.css("position", "fixed");

        var p = $("html");
        var off = $.extend({ top: 0, bottom: 0, left: 0, right: 0 }, _offset);
        var h = tgt.outerHeight(true);
        if (h == 0) {
            h = tgt[0].scrollHeight;
        }
        var w = tgt.outerWidth(true);

        var th = document.body.clientHeight;
        var tw = document.body.clientWidth;

        switch (_mode) {
            case "YCenter":
                tgt.css("top", (th - h) / 2 + off.top - off.bottom + 'px');
                break;
            case "XCenter":
                tgt.css("left", (tw - w + p[0].scrollLeft) / 2 + off.left - off.right + 'px');
                break;
            case "AllCenter":
                tgt.css("top", (th - h) / 2 + off.top - off.bottom + 'px');
                tgt.css("left", (tw - w + p[0].scrollLeft) / 2 + off.left - off.right + 'px');
                break;
            case "Cover":
                tgt.css('height', th + 'px').css('width', tw + 'px');
                break;
            case "Bottom":
                tgt.css("top", 0 - th).css("left", w - tw);
                break;
            default:
                tgt.offset(off);
                break;
        }
        p = null;
        off = null;
    },

    PosToBody: function PosToBody(_refElm, _elm, _pos, _offset, final) {
        /// <summary>
        /// 将Body中的某个子元素定位到指定元素附近(注意：窗口尺寸改变时需重新定位)
        /// </summary>
        /// <param name="_refElm">定位的参照目标元素</param>
        /// <param name="_elm">要改变位置的元素（必须是body的直接子元素,且是绝对定位）</param>
        /// <param name="方位">方向定义（cover,right,right-down,down,down-left,down-right,left-down,left,left-up,up,mid）</param>
        /// <param name="_offset">定位坐标偏移(可以是绝对数值，或相对参照目标的百分比)</param>

        var refpos = _refElm.offset(); //获取参照目标相对body的偏移坐标
        var refParent = _refElm.offsetParent();
        if (refParent.css('position') == 'relative') {
            refParent = refParent.offsetParent();
        }

        var rp_top = parseInt(refParent.css("paddingTop"));
        var rp_left = parseInt(refParent.css("paddingLeft"));

        var eh = _elm.outerHeight();
        var ew = _elm.outerWidth();
        var rw = _refElm.outerWidth();
        var rh = _refElm.outerHeight();

        if (!_offset) {
            _offset = { top: 0, left: 0 };
        } else {
            if (!_offset['top']) {
                _offset.top = 0;
            } else if (_offset.top.toString().slice(-1) === '%') {
                _offset.top = rh * parseFloat(_offset.top) / 100;
            }

            if (!_offset['left']) {
                _offset.left = 0;
            } else if (_offset.left.toString().slice(-1) === '%') {
                _offset.left = rw * parseFloat(_offset.left) / 100;
            }
        }
        var dst = {
            left: parseFloat(_elm.css("left")) || 0,
            top: parseFloat(_elm.css("top")) || 0
        };  //获取当前元素相对坐标

        var epos = _elm.offset();
        switch (_pos) {
            case "right-up":
                dst.top = refpos.top - eh - _offset.top;
                dst.left = refpos.left + rw + _offset.left;
                break;
            case "down-left":
                dst.top = refpos.top + rh - rp_top + _offset.top;
                dst.left = refpos.left + _offset.left;
                break;
            case "cover":
                dst.top = refpos.top - rp_top;
                dst.left = refpos.left - rp_left;
                break;
            case "down-right":
                dst.top = refpos.top + rh + _offset.top;
                dst.left = refpos.left + rw - ew + _offset.left;
                break;
            case "left-up":
                dst.top = refpos.top - eh + _offset.top;
                dst.left = refpos.left + _offset.left;
                break;
            default:
                break;
        }
        _elm[0].style.z = _refElm[0].style.z + 1;
        switch (_elm.css('position')) {
            case "absolute":
                _elm.css('top', dst.top).css('left', dst.left);
                break;
            default:
                _elm.css('top', dst.top).css('left', dst.left);
                break;
        }
        if (!final) {
            setTimeout(PosToBody, 100, _refElm, _elm, _pos, _offset, true);
        }

    },

    PosToParent: function PosToParent(_refElm, _elm, _pos) {
        /// <summary>
        /// 将同一个父元素中的某个元素以绝对定位方式定位在指定元素的相对位置上
        /// </summary>
        /// <param name="_refElm" type="type"></param>
        /// <param name="_elm" type="type"></param>
        /// <param name="_pos" type="type"></param>
        var rof = _refElm.offset();
        var tof = _elm.offset();
        var pof = _refElm.offsetParent().offset();
        switch (_pos) {
            case "Cover":
                if (_refElm.is("body")) {
                    var dst = {
                        "position": 'fixed',
                        "top": 0,
                        "z-index": _elm.css("zIndex") || 100,
                        "height": window.document.documentElement.clientHeight
                    }
                    _elm.css(dst);
                }
                else {
                    var pmode = _refElm.offsetParent().css("position");
                    var rmode = _refElm.css("position");

                    var dst = {
                        top: rof.top,
                        left: rof.left
                    };
                    if (pmode == "relative" || pmode == "static") {
                        if (rmode == "absolute") {
                            dst = {
                                top: rof.top - tof.top,
                                left: rof.left - tof.left
                            }
                        }
                        else {
                            dst = {
                                top: rof.top - tof.top,
                                left: rof.left - tof.left
                            }
                        }
                    }
                    else if (pmode == "absolute") {
                        if (rmode == "absolute") {
                            var p = _refElm.offsetParent();
                            dst = {
                                top: rof.top / p.height() * 100 + "%",
                                left: rof.left / p.width() * 100 + "%"
                            }
                        }
                        else {
                            dst = {
                                top: rof.top - tof.top,
                                left: rof.left - pof.left
                            }
                        }

                    }
                    else if (pmode == "fixed") {
                        dst = {
                            top: rof.top,
                            left: rof.left - pof.left
                        }
                    }
                    else {
                        dst = {
                            top: rof.top - tof.top,
                            left: rof.left - pof.left
                        }
                    }

                    _elm.css(dst);
                }

                break;
        }
    }
};
//#endregion

//#region 键盘帮助类
function KeypressMonitor() {
    var instance = this;
    instance.Global = {};
    var tgts = {};
    function onPress(ev) {
        var char = '';
        switch (ev.keyCode) {
            case 13:
                if (ev.ctrlKey) {
                    char = 'ctrl+enter';
                } else {
                    char = 'enter';
                }
                break;
            case 16:
                char = 'shift';
                break;
            case 17:
                char = 'ctrl';
                break;
            case 18:
                char = 'alt';
                break;
            case 20:
                char = 'capslock';
                break;
            case 32:
                char = 'space';
                break;
            case 186:
                if (ev.shiftKey) {
                    char = ':';
                } else {
                    char = ';';
                }
                break;
            case 188:
                if (ev.shiftKey) {
                    char = '<';
                } else {
                    char = ',';
                }
                break;
            case 190:
                if (ev.shiftKey) {
                    char = '>';
                } else {
                    char = '.';
                }
                break;
            default:
                char = String.fromCharCode(ev.keyCode);
                break;
        }
        ev = jQuery.Event(ev);
        var $elm = $(ev.originalEvent.srcElement);
        ev.Dom = $elm;
        var id = $elm.attr('id');

        //先看看有没有全局事件绑定
        if (instance.Global[char] && instance.Global[char].length > 0) {
            for (var i = instance.Global[char].length - 1; i > -1; i--) {
                instance.Global[char][i].call(this, ev, char);
                if (ev.isPropagationStopped()) {
                    break;
                }
            }
        } else if (instance.Global['*'] && instance.Global['*'].length > 0) {
            for (var i = instance.Global[char].length - 1; i > -1; i--) {
                instance.Global['*'][i].call(this, ev, char);
                if (ev.isPropagationStopped()) {
                    break;
                }
            }
            //instance.Global['*'][0].call(this, ev, char);
        } else { }

        //再看看有没有绑定特定元素
        if (tgts[id]) {
            if (char != '' && !tgts[id].handed) {
                tgts[id].handed = true;
                notifyKeyEvent(char, id, ev);
            } else {
                tgts[id].handed = false;
            }
        }
    };

    function onDown(ev) {
        var char = '';
        switch (ev.keyCode) {
            case 8:
                char = 'backspace';
                break;
            case 9:
                char = 'tab';
                break;
            case 40:
                char = 'down';
                break;
            case 38:
                char = 'up';
                break;
            case 27:
                char = 'esc';
                break;
        }
        if (ObjHelper.IsEmpty(char)) {
            return;
        }
        ev = jQuery.Event(ev);
        var $elm = $(ev.originalEvent.srcElement);
        ev.Dom = $elm;
        var id = $elm.attr('id');
        //先看看有没有全局事件绑定
        if (instance.Global[char] && instance.Global[char].length > 0) {
            for (var i = instance.Global[char].length - 1; i > -1; i--) {
                instance.Global[char][i].call(this, ev, char);
                if (ev.isPropagationStopped()) {
                    break;
                }
            }
        } else if (instance.Global['*'] && instance.Global['*'].length > 0) {
            for (var i = instance.Global[char].length - 1; i > -1; i--) {
                instance.Global['*'][i].call(this, ev, char);
                if (ev.isPropagationStopped()) {
                    break;
                }
            }
            //instance.Global['*'][0].call(this, ev, char);
        } else { }

        //再看看有没有绑定特定元素
        if (tgts[id]) {
            if (char != '' && !tgts[id].handed) {
                tgts[id].handed = true;
                notifyKeyEvent(char, id, ev);
            } else {
                tgts[id].handed = false;
            }
        }
    };

    function onInput(ev) {
        ev = jQuery.Event(ev);
        var $elm = $(ev.originalEvent.srcElement);
        ev.Dom = $elm;
        var id = $elm.attr('id');
        var char = '';
        var v = $elm.vl();
        char = v.slice(v.length - 1, v.length);
        switch (char) {
            case "。":
                char = '.';
                break;
            case "，":
                char = ',';
                break;
            case "：":
                char = ":";
                break;
        }
        //先看看有没有全局事件绑定
        if (instance.Global[char] && instance.Global[char].length > 0) {
            for (var i = instance.Global[char].length - 1; i > -1; i--) {
                instance.Global[char][i].call(this, ev, char);
                if (ev.isPropagationStopped()) {
                    break;
                }
            }
        } else if (instance.Global['*'] && instance.Global['*'].length > 0) {
            for (var i = instance.Global[char].length - 1; i > -1; i--) {
                instance.Global['*'][i].call(this, ev, char);
                if (ev.isPropagationStopped()) {
                    break;
                }
            }
        } else { }

        //再看看有没有绑定特定元素
        if (tgts[id]) {
            if (char != '' && !tgts[id].handed) {
                tgts[id].handed = true;
                notifyKeyEvent(char, id, ev);
            } else {
                tgts[id].handed = false;
            }
        }
    };

    function notifyKeyEvent(char, id, ev) {
        ev.Char = char;
        //首先看是否针对特定字符绑定了处理函数
        var hs = tgts[id][char];
        if (hs) {
            for (var i = hs.length - 1; i > -1; i--) {
                if (ObjHelper.IsFunc(hs[i])) {
                    hs[i](ev, char);
                    if (ev.isPropagationStopped()) {
                        break;
                    }
                }
            }
        } else {
            //如果没有，看是否针对任意按键都绑定了处理事件
            hs = tgts[id]['*'];
            if (hs) {
                for (var i = hs.length - 1; i > -1; i--) {
                    if (ObjHelper.IsFunc(hs[i])) {
                        hs[i](ev, char);
                        if (ev.isPropagationStopped()) {
                            break;
                        }
                    }
                }
            }
        }
    };

    window.onkeydown = onDown;
    window.onkeypress = onPress;
    window.oninput = onInput;

    this.on = function (_elm, _char, _fn) {
        /// <summary>
        /// 将指定方法绑定到目标Dom元素的特殊键盘事件
        /// </summary>
        /// <param name="_elm">要监视其键盘事件的元素</param>
        /// <param name="_char">要监视的特定输入值【enter,esc,space,dot,slash,backslash,backspace,colon】</param>
        /// <param name="_fn">要回调的方法</param>
        var id = _elm.ID();
        var char = _char.toString().trim();
        if (!id) {
            id = 'id' + Math.random();
            _elm.ID(id);
        }

        if (!tgts[id]) {
            tgts[id] = {};
            tgts[id][char] = [];
        } else if (!tgts[id][char]) {
            tgts[id][char] = [];
        }
        tgts[id][char].push(_fn);
        return instance;
    };

    this.off = function (_elm, _char, _fn) {
        /// <summary>
        /// 解除特定的或所有的事件绑定
        /// </summary>
        /// <param name="_elm"></param>
        /// <param name="_char"></param>
        /// <param name="_fn">指定要解除的方法，如果为空，则解除所有的事件绑定</param>
        var id = _elm.ID();
        if (ObjHelper.IsEmpty(_char)) {
            if (tgts.hasOwnProperty(id)) {
                ObjHelper.DisposeObj(tgts[id]);
                tgts[id] = null;
            }
        } else {
            //TODO：解除对特定键盘输入值的监控
        }
        return instance;
    };

    this.globalOn = function (_char, _fn) {
        /// <summary>
        /// 绑定全局特定按键（只有最后注册的方法会得到键盘消息，除非此方法被globalOff调用移除）
        /// </summary>
        /// <param name="_char"></param>
        /// <param name="_fn"></param>
        /// <returns type=""></returns>
        if (!ObjHelper.IsFunc(_fn)) {
            return this;
        }
        if (instance.Global.hasOwnProperty(_char)) {
            var chs = instance.Global[_char];
            //for (var i = 0; i < chs.length; i++) {
            //    if (chs[i] === _fn) {
            //        chs.swap(0, i);
            //        return this;
            //    }
            //}
            chs.push(_fn);
            return this;
        } else {
            instance.Global[_char] = [];
            instance.Global[_char].push(_fn);
            return this;
        }
    };

    this.globalOff = function (_char, _fn) {
        /// <summary>
        /// 解除绑定的全局按键事件
        /// </summary>
        /// <param name="_char"></param>
        /// <param name="_fn"></param>
        /// <returns type=""></returns>
        if (!ObjHelper.IsFunc(_fn)) {
            return this;
        }
        if (instance.Global.hasOwnProperty(_char)) {
            var hs = instance.Global[_char];
            for (var i = 0; i < hs.length; i++) {
                if (hs[i] == _fn) {
                    hs.splice(i, 1);
                }
            }
            return this;
        }
        return this;
    };

    this.Dispose = function () {
        $(window).off('keypress', onPress).off('keydown', onDown);
        window.oninput = null;
        ObjHelper.DisposeObj(instance);
        instance = null;
    };

    return instance;
}
if (!window.KeybordHelper) {
    var KeybordHelper = new KeypressMonitor();
};

//#endregion

Math.diff = function (num1, num2) {
    /// <summary>
    /// 精确比较两个浮点数的差异值
    /// </summary>
    /// <param name="num1" type="Number">数值1</param>
    /// <param name="num2" type="Number">数值2</param>
    /// <returns type="Number">差异值</returns>
    var pow = 10000;
    return (num1 * pow - num2 * pow) / 10000;
}

//#region Array对象操作方法扩展
Array.prototype.eq = function (_index) {
    return this[_index];
};
Array.prototype.findValue = function (v) {
    if (this.length == 0 || !v) { return null; };
    var vv = v.toString();
    for (var i = 0; i < this.length; i++) {
        if (this[i].toString() === vv) {
            return this[i];
        }
    }
    return null;
};
Array.prototype.findObj = function (_field, _value, _newobj, deepsearch) {
    /// <summary>
    /// 在数组中查找具有指定属性或指定属性的值符合条件的第一个对象
    /// </summary>
    /// <param name="_field" type="type">属性名</param>
    /// <param name="_value" type="type">筛选值，不指定则返回第一个指定名称属性值不为null的</param>
    /// <param name="_newobj" type="type"></param>
    /// <param name="deepsearch" type="boolean">执行树结构的深度搜索</param>
    /// <returns type=""></returns>
    if (this.length == 0) {
        return null;
    };
    if (_value !== null && _value !== undefined) {
        for (var i = 0; i < this.length; i++) {
            if (this[i].hasOwnProperty(_field) && this[i][_field] == _value) {
                if (!ObjHelper.IsEmpty(_newobj)) {
                    this[i] = _newobj;
                }
                return this[i];
            }
            else if (deepsearch && this[i].children && this[i].children instanceof Array) {
                var d = this[i].children.findObj(_field, _value, _newobj, deepsearch);
                if (d !== null) {
                    return d;
                }
            }
            else {

            }
        }
    }
    else {
        for (var i = 0; i < this.length; i++) {
            if (this[i].hasOwnProperty(_field)) {
                if (!ObjHelper.IsEmpty(_newobj)) {
                    this[i] = _newobj;
                }
                return this[i];
            }
            else if (deepsearch && this[i].children && this[i].children instanceof Array) {
                var d = this[i].children.findObj(_field, _value, _newobj, deepsearch);
                if (d) {
                    return d;
                }
            }
            else {

            }
        };
    };
    return null;
};
Array.prototype.findObjIndex = function (_field, _value, _newobj) {
    if (this.length == 0) {
        return -1;
    };
    for (var i = 0; i < this.length; i++) {
        if (this[i].hasOwnProperty(_field) && this[i][_field] == _value) {
            if (!ObjHelper.IsEmpty(_newobj)) {
                this[i] = _newobj;
            }
            return i;
        }
        else {

        }
    };
    return -1;
};
Array.prototype.filterBy = function (_field, _value) {
    if (ObjHelper.IsFunc(_field)) {
        return this.filter(_field);
    };
    var rsult = [];
    if (this.length == 0) {
        return rsult;
    };
    if (!ObjHelper.IsEmpty(_value)) {
        for (var i = 0; i < this.length; i++) {
            if (this[i].hasOwnProperty(_field) && this[i][_field] == _value) {
                rsult.push(this[i]);
            }
        };
    } else {
        for (var i = 0; i < this.length; i++) {
            if (this[i].hasOwnProperty(_field) && this[i][_field] !== null && this[i][_field] !== undefined && this[i][_field] !== NaN) {
                rsult.push(this[i]);
            }
        };
    };
    return rsult;
};
Array.prototype.joinAttr = function (_field) {
    if (this.length == 0) {
        return [];
    } else {
        var rtn = [];
        for (var i = 0; i < this.length; i++) {
            if (this[i][_field]) {
                rtn.push(this[i][_field]);
            }
        };
        return rtn;
    };
};
Array.prototype.merge = function (_array, _pk, _fk) {
    var tmp = [];
    for (var i = 0; i < _array.length; i++) {
        var p = this.findObj(_pk, _array[i][_fk]);
        if (!p) {
            tmp.push(_array[i]);
        }
    };
    return this.push.apply(this, tmp);
};
Array.prototype.removeBy = function (_field, _value) {
    for (var i = 0; i < this.length; i++) {
        if (this[i][_field] && this[i][_field] === _value) {
            this.splice(i, 1);
        }
    };
    return this;
};
Array.prototype.removeOn = function (_value) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] && this[i] === _value) {
            this.splice(i, 1);
        }
    };
    return this;
};
Array.prototype.asTree = function (k, pk) {
    /// <summary>
    /// 根据指定主键和父级键将当前平行数组转换为一个标准树型结构
    /// </summary>
    /// <param name="k" type="type"></param>
    /// <param name="pk" type="type"></param>
    if (this.length < 2) {
        return this;
    };
    var rtn = [];

    for (var i = 0; i < this.length; i++) {
        var pid = this[i][pk];
        var pobj = this.findObj(k, pid);
        if (pobj !== null) {
            if (!pobj.children) {
                if (Vue) {
                    Vue.set(pobj, "children", []);
                }
                else {
                    pobj.children = [];
                }

            }
            pobj.children.push(this[i]);
            pobj._ex = true;
        }
        else {
            rtn.push(this[i]);
        }

        this[i]._sub_expanded = true;
    };

    return rtn;
};
Array.prototype.appendTreeNode = function (k, pid, obj) {
    /// <summary>
    /// 根据指定主键和父级键向当前标准树型结构中添加节点
    /// </summary>
    /// <param name="k" type="type"></param>
    /// <param name="pk" type="type"></param>
    /// <param name="obj" type="type"></param>
    var pobj = this.findObj(k, pid, null, true);
    if (pobj != null) {
        if (!pobj.children) {
            if (Vue) {
                Vue.set(pobj, "children", []);
            }
            else {
                pobj.children = [];
            }
        }
        pobj.children.push(obj);
        pobj._ex = true;
    }
    obj._sub_expanded = true;
    return this;
};
Array.prototype.distinc = function (_field) {
    /// <summary>
    /// 根据指定键对数组对象去重并返回一个新数组
    /// </summary>
    var tmp = {};
    var tmpArray = [];
    this.forEach(function (a) {
        if (a.hasOwnProperty(_field) && !tmp.hasOwnProperty(a[_field])) {
            tmp[a._field] = 1;
            tmpArray.push(a);
        }
    });
    tmp = null;
    return tmpArray;
}
//#endregion

//#region String扩展方法
String.prototype.toJSON = function () {
    /// <summary>
    /// 将JSON格式的字符串转为标准的JSON对象
    /// </summary>
    /// <returns type=""></returns>
    if (this.length > 2) {
        return JSON.parse(this.replace(/&quot;/g, '\"').replace(/&gt;/g, '>').replace(/&lt;/g, '<'));
    } else {
        return null;
    }
};

String.prototype.noHtml = function () {
    /// <summary>
    /// 去除字符串中的Html标记
    /// </summary>
    /// <returns type=""></returns>
    return this.replace(/<\/?[^>]*>/g, '').replace(/[ | ]*\n/g, '\n').replace(/&nbsp;/ig, '').trim();
};

String.prototype.MD5 = function () {
    return $.md5(this);
};

var I64BIT_TABLE = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "_", "-", "/", "?", "&"];

String.prototype.hashCode = function () {
    var hash = 5381;
    var i = this.length - 1;
    for (; i > -1; i--)
        hash += (hash << 5) + this.charCodeAt(i);
    var value = hash & 0x7FFFFFFF;

    var retValue = '';
    do {
        retValue += I64BIT_TABLE[value & 0x3F];
    }
    while (value >>= 6);

    return retValue;
};

String.prototype.md4 = function () {
    var v = "";
    var p = this.length;

    for (var i = 0; i < this.length; i++) {
        v += "-" + (this.charCodeAt(i) - p).toString(16);
    };
    return p.toString() + v;
};

(function ($) {
    var rotateLeft = function rotateLeft(lValue, iShiftBits) {
        return lValue << iShiftBits | lValue >>> 32 - iShiftBits;
    };

    var addUnsigned = function addUnsigned(lX, lY) {
        var lX4, lY4, lX8, lY8, lResult;
        lX8 = lX & 0x80000000;
        lY8 = lY & 0x80000000;
        lX4 = lX & 0x40000000;
        lY4 = lY & 0x40000000;
        lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
        if (lX4 & lY4) return lResult ^ 0x80000000 ^ lX8 ^ lY8;
        if (lX4 | lY4) {
            if (lResult & 0x40000000) return lResult ^ 0xC0000000 ^ lX8 ^ lY8; else return lResult ^ 0x40000000 ^ lX8 ^ lY8;
        } else {
            return lResult ^ lX8 ^ lY8;
        }
    };

    var F = function F(x, y, z) {
        return x & y | ~x & z;
    };

    var G = function G(x, y, z) {
        return x & z | y & ~z;
    };

    var H = function H(x, y, z) {
        return x ^ y ^ z;
    };

    var I = function I(x, y, z) {
        return y ^ (x | ~z);
    };

    var FF = function FF(a, b, c, d, x, s, ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };

    var GG = function GG(a, b, c, d, x, s, ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };

    var HH = function HH(a, b, c, d, x, s, ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };

    var II = function II(a, b, c, d, x, s, ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };

    var convertToWordArray = function convertToWordArray(string) {
        var lWordCount;
        var lMessageLength = string.length;
        var lNumberOfWordsTempOne = lMessageLength + 8;
        var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - lNumberOfWordsTempOne % 64) / 64;
        var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16;
        var lWordArray = Array(lNumberOfWords - 1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while (lByteCount < lMessageLength) {
            lWordCount = (lByteCount - lByteCount % 4) / 4;
            lBytePosition = lByteCount % 4 * 8;
            lWordArray[lWordCount] = lWordArray[lWordCount] | string.charCodeAt(lByteCount) << lBytePosition;
            lByteCount++;
        }
        lWordCount = (lByteCount - lByteCount % 4) / 4;
        lBytePosition = lByteCount % 4 * 8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | 0x80 << lBytePosition;
        lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
        lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
        return lWordArray;
    };

    var wordToHex = function wordToHex(lValue) {
        var WordToHexValue = "",
            WordToHexValueTemp = "",
            lByte,
            lCount;
        for (lCount = 0; lCount <= 3; lCount++) {
            lByte = lValue >>> lCount * 8 & 255;
            WordToHexValueTemp = "0" + lByte.toString(16);
            WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2);
        }
        return WordToHexValue;
    };

    var uTF8Encode = function uTF8Encode(string) {
        string = string.replace(/\x0d\x0a/g, "\x0a");
        var output = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                output += String.fromCharCode(c);
            } else if (c > 127 && c < 2048) {
                output += String.fromCharCode(c >> 6 | 192);
                output += String.fromCharCode(c & 63 | 128);
            } else {
                output += String.fromCharCode(c >> 12 | 224);
                output += String.fromCharCode(c >> 6 & 63 | 128);
                output += String.fromCharCode(c & 63 | 128);
            }
        }
        return output;
    };

    $.extend({
        md5: function md5(string) {
            var x = Array();
            var k, AA, BB, CC, DD, a, b, c, d;
            var S11 = 7,
                S12 = 12,
                S13 = 17,
                S14 = 22;
            var S21 = 5,
                S22 = 9,
                S23 = 14,
                S24 = 20;
            var S31 = 4,
                S32 = 11,
                S33 = 16,
                S34 = 23;
            var S41 = 6,
                S42 = 10,
                S43 = 15,
                S44 = 21;
            string = uTF8Encode(string);
            x = convertToWordArray(string);
            a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
            for (k = 0; k < x.length; k += 16) {
                AA = a; BB = b; CC = c; DD = d;
                a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
                d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
                c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
                b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
                a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
                d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
                c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
                b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
                a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
                d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
                c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
                b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
                a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
                d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
                c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
                b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
                a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
                d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
                c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
                b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
                a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
                d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
                c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
                b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
                a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
                d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
                c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
                b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
                a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
                d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
                c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
                b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
                a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
                d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
                c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
                b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
                a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
                d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
                c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
                b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
                a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
                d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
                c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
                b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
                a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
                d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
                c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
                b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
                a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
                d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
                c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
                b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
                a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
                d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
                c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
                b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
                a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
                d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
                c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
                b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
                a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
                d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
                c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
                b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
                a = addUnsigned(a, AA);
                b = addUnsigned(b, BB);
                c = addUnsigned(c, CC);
                d = addUnsigned(d, DD);
            }
            var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
            return tempValue.toLowerCase();
        }
    });
})(jQuery);

//#endregion

//#region Object扩展方法
function getXML(jsonObj, root) {
    /// <summary>
    /// 将一个JSON对象转换为XML格式的字符串
    /// </summary>
    /// <param name="jsonObj" type="type"></param>
    /// <param name="root" type="type"></param>
    /// <returns type=""></returns>
    var xml = "";
    if (jsonObj instanceof Array) {
        for (var i = 0; i < jsonObj.length; i++) {
            xml += getXML(jsonObj[i], true);
        }
        return "<xml>" + xml + "</xml>";
    } else {
        for (var f in jsonObj) {
            if (jsonObj[f] && jsonObj.hasOwnProperty(f)) {
                xml += toXml(jsonObj[f], f, "");
            }
        }
    }
    if (!root) {
        xml = "<xml>" + xml.replace(/\t|\n/g, "") + "</xml>";
    } else {
        xml = xml.replace(/\t|\n/g, "");
    }

    return xml;
};

function toXml(v, name, ind) {
    var xml = "";
    if (v instanceof Array) {
        for (var i = 0, n = v.length; i < n; i++) xml += ind + toXml(v[i], name, ind + "\t") + "\n";
    } else if (typeof v == "object") {
        var hasChild = false;
        xml += ind + "<" + name;
        for (var m in v) {
            if (m.charAt(0) == "@") xml += " " + m.substr(1) + "=\"" + v[m].toString().replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/\'/g, " &apos;").replace(/&/g, '&amp;') + "\""; else hasChild = true;
        }
        xml += hasChild ? ">" : "/>";
        if (hasChild) {
            for (var m in v) {
                if (m == "#text") xml += v[m]; else if (m == "#cdata") xml += "<![CDATA[" + v[m] + "]]>"; else if (m.charAt(0) != "@") xml += toXml(v[m], m, ind + "\t");
            }
            xml += (xml.charAt(xml.length - 1) == "\n" ? ind : "") + "</" + name + ">";
        }
    } else if (typeof v == "function") {
        return "";
    } else if (v !== undefined && v !== null) {
        xml += ind + "<" + name + ">" + v.toString().replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/\'/g, " &apos;").replace(/&/g, '&amp;') + "</" + name + ">";
    } else { }
    return xml;
};

function errFormate(rtn, withSrc) {
    /// <summary>
    /// 根据前端配置格式化含有错误信息的标准返回结果
    /// </summary>
    if (rtn.IsPositive) {
        return "";
    }
    if (!window.RES || !RES.ERROR || !RES.ERROR[rtn.ErrorSrc]) {
        if (withSrc) {
            return {
                msg: "错误代码[" + rtn.ErrorCode + "]",
                from: "来自：" + rtn.ErrorSrc
            }
        }
        else {
            return "服务器组件&lt;" + rtn.ErrorSrc + "&gt;返回了错误代码[" + rtn.ErrorCode + "]";
        }

    }
    else {
        var er = RES.ERROR[rtn.ErrorSrc];
        if (er[rtn.ErrorCode]) {
            if (!withSrc) {
                return er[rtn.ErrorCode];
            }
            else {
                return {
                    msg: er[rtn.ErrorCode],
                    from: "来自：" + er.ErrSrc
                }
            }
        }
        else {
            if (!withSrc) {
                return "服务器返回了一个错误，但没有说明具体原因";
            }
            else {
                return {
                    msg: "服务器返回了一个错误，但没有说明具体原因",
                    from: "系统"
                }
            }
        }
    }
};

JSON.merge = function (targetObj, fromObj,excludeNewProp) {
    /// <summary>
    /// 深度合并目标Json对象到指定的Json对象
    /// </summary>
    /// <param name="targetObj" type="type">合并目标</param>
    /// <param name="fromObj" type="type">合并来源，如果有相同属性，将覆盖目标对象中的值</param>
    /// <param name="excludeNewProp" type="boolean">是否排除目标对象本来没有的属性</param>

    if (!targetObj || !fromObj || !targetObj instanceof Object || !targetObj instanceof Object) {
        return targetObj;
    };

    if (fromObj instanceof Array && targetObj instanceof Array) {
        for (var i = 0; i < fromObj.length; i++) {
            if (fromObj[i] instanceof Object && targetObj[i]) {
                targetObj[i] = JSON.clone(fromObj[i]);
            }
            else {
                targetObj[i] = fromObj[i];
            }
        }
    }
    else {
        for (var p in fromObj) {
            if (targetObj.hasOwnProperty(p) && targetObj[p] instanceof Object) {
                targetObj[p] = JSON.clone(fromObj[p]);
            }
            else if (!excludeNewProp) {
                targetObj[p] = fromObj[p];
            }
            else {

            }
        }
    }
    return targetObj;
};

JSON.clone = function (obj) {
    if (!obj || !obj instanceof Object) {
        return obj;
    }
    return JSON.parse(JSON.stringify(obj));
};

function isSame (a,b) {
    if (!a||!b) {
        return false;
    }
    var astr = JSON.stringify(a).split('').sort().toString();
    var bstr = JSON.stringify(b).split('').sort().toString();
    return astr === bstr;
};

//#endregion

//#region Number对象的扩展方法
Number.prototype.roundTo = function (fix) {
    /// <summary>
    /// 高精度四舍五入到指定位数
    /// </summary>
    /// <param name="fix"></param>
    return Math.round(this * Math.pow(10, fix)) / Math.pow(10, fix);
};
Number.prototype.formatPercent = function (fix, noceil) {
    /// <summary>
    /// 带百分号，并可以指定小数部分的位数
    /// </summary>
    /// <param name="fix" type="type">小数位最大长度</param>
    /// <param name="noceil" type=boolean>如果小数位部分太小，是否在最后一位上进位表达[默认进位]</param>
    /// <returns type=""></returns>
    if (fix === undefined || fix === null) {
        fix = 0;
    };

    var fStr = (this * 100).toString();
    var dot = fStr.indexOf('.');

    if (dot < 0) {
        return fStr + '%';
    }
    else {
        var pStr = fStr.substring(0, dot);
        var eStr = "0." + fStr.substring(dot + 1, fStr.length);
        var eValue = Math.floor(parseFloat(eStr) * Math.pow(10, fix));
        if (eValue == 0 && !noceil) {
            return pStr + "." + (1).fixLength(fix) + "%";
        }
        else {
            return pStr + "." + eValue.fixLength(fix) + "%";
        }

    }
};
Number.prototype.toThousands = function (fix) {
    /// <summary>
    /// 将数字按千分位分隔符
    /// </summary>
    /// <param name="fix" type="type">小数位固定长度</param>
    /// <returns type=""></returns>
    var src = (this || 0).toString().split('.');
    var num = src[0];
    var result = "";
    if (src.length > 1) {
        if (fix === undefined || fix === null || !parseInt(fix)) {
            result = '.' + src[1];
        }
        else {
            var tail = parseFloat('0.' + src[1]).toFixed(fix);
            result = '.' + tail.split('.')[1];
        }
    }

    while (num.length > 3) {
        result = ',' + num.slice(-3) + result;
        num = num.slice(0, num.length - 3);
    }
    if (num) {
        result = num + result;
    }
    if (src.length == 1 && fix !== undefined && fix !== null && parseInt(fix)) {
        var tail = (1.0).toFixed(fix);
        result = result + '.' + tail.toString().split('.')[1];
    }
    return result;
};
Number.prototype.fixLength = function (len) {
    /// <summary>
    /// 将数字格式化为固定长度的字符串[前缀补0]
    /// </summary>
    /// <param name="len" type="type"></param>
    /// <returns type=""></returns>
    var ln = this.toString().length;
    var num = this;
    while (ln < len) {
        num = "0" + num;
        ln += 1;
    }
    return num;
};
//#endregion

//#region 日期对象的扩展方法
Date.prototype.formate = function (parten) {
    if (!parten) {
        parten = "yyyy-MM-dd HH:mm:ss";
    };

    var o = {
        "M+": this.getMonth() + 1,                 /*月份 */
        "d+": this.getDate(),                    /*日 */
        "h+": this.getHours(),                   /*小时*/
        "H+": this.getHours(),
        "m+": this.getMinutes(),                 /*分 */
        "s+": this.getSeconds(),                 /*秒 */
        "q+": Math.floor((this.getMonth() + 3) / 3), /*季度 */
        "S": this.getMilliseconds()             /*毫秒*/
    };
    if (/(y+)/.test(parten)) {

        parten = parten.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    }
    for (var k in o) {
        if (new RegExp("(" + k + ")").test(parten)) {
            parten = parten.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        }
    }
    return parten;

}
Date.prototype.diffOf = function (startDate) {
    /// <summary>
    /// 获取当前时间与起始时间的大致间隔
    /// </summary>
    /// <param name="startDate" type="Date"></param>
    if (startDate === undefined || startDate === null) {
        startDate = new Date();
    }
    else if (!(startDate instanceof Date)) {
        startDate = new Date(startDate);
    }
    else {
    };

    let rtn = {
        year: 0,
        month: 0,
        day: 0,
        hour: 0,
        min: 0,
        second: 0
    };

    let tickets = this.getTime() - startDate.getTime();   //时间差的毫秒数        

    //计算出总计相差  
    rtn.day = Math.floor(tickets / (24 * 3600 * 1000));
    rtn.year = this.getYear() - startDate.getYear();
    rtn.month = rtn.year * 12 + (this.getMonth() - startDate.getMonth());
    if (rtn.month < 12 && rtn.year < 0) {
        rtn.year += 1;
    };

    if (rtn.day < 30 && rtn.month < 0) {
        rtn.month += 1;
    };

    /*计算天数后剩余的毫秒数*/
    let leftTickts = tickets % 86400000;
    rtn.hour = Math.floor(leftTickts / 3600000);
    if (rtn.hour < 0) {
        rtn.hour += rtn.day * -24;
    }
    
    //rtn.day += 1;  /*加上当天修正*/

    /*计算小时数后剩余的毫秒数*/
    leftTickts = leftTickts % 3600000;
    rtn.min = Math.floor(leftTickts / 60000);

    /*计算分钟数后剩余的毫秒数*/
    leftTickts = leftTickts % 60000;
    rtn.second = Math.floor(leftTickts / 1000);

    return rtn;
};
Date.prototype.addDays = function (d) {
    if (d && $.isNumeric(d)) {
        var nt = (d * 86400000) + this.getTime();
        return new Date(nt);
    }
    else {
        return this;
    }
};
//#endregion

//#region 用数组模拟的双向队列
function Queue(srcArray) {
    var elms = (srcArray && Array.isArray(srcArray)) ? srcArray : [];

    this.Append = function (obj) {
        /// <summary>
        /// 向队列尾部追加一个元素
        /// </summary>
        /// <param name="obj"></param>
        /// <returns type="Queue"></returns>
        elms.push(obj);
        return this;
    };

    this.Prepend = function (obj) {
        /// <summary>
        /// 向队列头部插入一个元素
        /// </summary>
        /// <param name="obj"></param>
        /// <returns type="Queue"></returns>
        var tmp = [obj];
        elms = tmp.concat(elms);
        return this;
    };

    this.Dequeue = function () {
        /// <summary>
        /// 移除并返回队列头部的元素
        /// </summary>
        if (elms.length > 0) {
            return elms.shift();
        } else {
            return null;
        }
    };

    this.Length = function () {
        return elms.length;
    };
    return this;
};

//#endregion

//全站基础UI逻辑
if (!window.SoBiz) {
    window.RQList = {};
    window.url_parser = new RegExp(/(\/[\S\s]*)\??([\S]*)#?([\S]*?)/gi);
    $.ajaxSetup({
        cache: true,
        async: true,
        timeout: 60000,
        contentType: "application/x-www-form-urlencoded; charset=utf-8",
        xhr: function () {
            var x = new XMLHttpRequest();
            x.withCredentials = true;
            this.rawXHR = x;
            return x;
        },
        beforeSend: function beforeSend(rq, ev) {
            //针对html和JSON请求判断动作权限
            var dtype = ev.dataType ? ev.dataType.toLowerCase() : "";
            var uri = document.createElement('a');
            uri.href = ev.url;

            var path = uri.pathname.toLowerCase();
            //针对IE有时pathname会没有前面的斜杠进行处理
            if (path.substr(0, 1) !== '/') {
                path = '/' + path;
            };

            if ((dtype == "html" || dtype == "json")) {
                console.log("TODO:对于html请求和json请求进行基于URL的权限筛选");
                //对于html请求和json请求进行基于URL的权限筛选
            };


            //阻止重复的POST提交
            if (this.type == "POST" && (RQList[path] != null && RQList[path] == 1)) {
                console.log("抱歉，此操作禁止重复执行，请等待前次请求执行完毕" + path);
                rq.abort();
                return false;
            }
            else if (this.type == "POST" && this.data && this.data.indexOf("_alone=false") == -1) {
                //如果首次POST请求，且未指定关闭独占模式，添加到监视列表
                RQList[path] = 1;
                this._rootPath = path;
            }
            else {
            }

            //为POST请求增加额外的验证头
            if (this.type == "POST" && $.Cookie("liber_session")) {
                rq.setRequestHeader("X-Liber-ClientID", $.Cookie("liber_session").MD5());
            }

            //TODO:对于一模一样的Get请求进行限流处理
        },
        complete: function complete(rtn, ev) {
            if (this._rootPath) {
                RQList[this._rootPath] = -1;
            }
        },
        error: function (rtn, er) {
            if (this._rootPath) {
                RQList[this._rootPath] = -1;
            }
        }
    });

    //业务对象标准生存周期状态
    window.BizStatus = {
        Unknow: -1,
        Draft: 1,
        Active: 2,
        Aborted: 3,
        Completed: 4,
        Pending: 5,
        getString: function (s) {
            switch (s) {
                case 0:
                    return 'Unknow';
                case 1:
                    return 'Draft';
                case 2:
                    return 'Active';
                case 3:
                    return 'Aborted';
                case 4:
                    return 'Completed';
                case 5:
                    return 'Pending';
                default:
                    return '';
            }
        },
        fromString: function (str) {
            switch (str.toLowerCase()) {
                case 'draft':
                    return 1;
                case 'active':
                    return 2;
                case 'aborted':
                    return 3;
                case 'completed':
                    return 4;
                case 'pending':
                    return 5;
                default:
                    return -1;
            }
        }
    };
    Vue.prototype.BizStatus = window.BizStatus;

    window.SoBiz = {
        SessionID: function (fnOnSuccess) {
            /// <summary>
            /// 获取当前客户端的唯一标识
            /// </summary>
            /// <param name="fnOnSuccess" type="function">回调方法</param>
            if (!$.Cookie("liber_session")) {
                $.ajax({
                    url: "/api/SoBiz/NewSession",
                    type: "GET",
                    success: function () { fnOnSuccess && fnOnSuccess($.Cookie("liber_session")); },
                    error: SoBiz.onNetFail
                });
            }
            else {
                fnOnSuccess && fnOnSuccess($.Cookie("liber_session"));
            }
        },
        NewSession: function (fn) {
            $.Cookie("liber_session", null);
            $.ajax({
                url: "/api/SoBiz/NewSession",
                type: "GET",
                success: function () { fn && fn($.Cookie("liber_session")); },
                error: SoBiz.onNetFail
            });
        },
        GetJSON: function (url, param, onSuccess, onErr) {
            /// <summary>
            /// 封装JQ的ajax请求JSON方法，提供错误回调
            /// </summary>
            /// <param name="url" type="type"></param>
            /// <param name="param" type="type"></param>
            /// <param name="onSuccess" type="type"></param>
            /// <param name="onErr" type="type">网络请求失败处理【不提供，则采用默认处理方式，401会转入登录页】</param>
            return $.ajax({
                url: "/api" + url,
                type: 'GET',
                dataType: 'json',
                data: param,
                success: onSuccess,
                error: onErr || SoBiz.onNetFail
            });
        },
        Any: function () {
            return new SoBiz.taskmng();
        },
        POST: function (url, upData, onSuccess, onErr, _alone, rspType) {
            /// <summary>
            /// 封装JQ的ajax请求POST方法，提供失败回调
            /// </summary>
            /// <param name="url" type="string"></param>
            /// <param name="upData" type="json|string"></param>
            /// <param name="onSuccess" type="function"></param>
            /// <param name="onErr" type="function">网络请求失败处理【不提供，则采用默认处理方式，401会转入登录页】</param>
            /// <param name="_alone" type="boolean">默认POST请求采用独占模式，不允许重复提交，如果有需要，可设置此参数为false</param>
            /// <param name="rspType" type="string">自定义返回的数据类型</param>
            if (!upData) {
                upData = {};
            }

            upData._alone = _alone ? _alone : true;
            var opt = {
                url: "/api" + url,
                type: 'POST',
                data: upData,
                cache: false,
                success: function (rtn, status, xhr) {
                    if (this.rawXHR && (this.rawXHR.responseType == 'blob' || this.rawXHR.responseType == 'arraybuffer')) {
                        var hrs = xhr.getAllResponseHeaders();
                        var cc = hrs.match(/(content-disposition:).*(\s)/g);
                        var fname = "下载文档";
                        if (cc && cc.length > 0) {
                            var tf = cc[0].trim().match(/(filename%3d)+.*$/g);
                            if (tf && tf.length > 0) {
                                tf[0] = tf[0].replace("filename%3d", "");
                                fname = decodeURIComponent(decodeURIComponent(tf[0].trim()));
                            }
                        }
                        if (this.rawXHR.response && this.rawXHR.response.size > 0) {
                            rtn = {
                                IsPositive: true,
                                Data: this.rawXHR.response
                            }
                            var fileUrl = URL.createObjectURL(this.rawXHR.response);
                            var a = document.createElement("a");
                            document.body.appendChild(a);
                            a.style = "display: none";
                            a.href = fileUrl;
                            a.setAttribute("exp", "true");
                            try {
                                a.download = fname;
                                a.click();
                            }
                            catch (ex) {
                                window.navigator.msSaveBlob(this.rawXHR.response, fname);
                            }
                            document.body.removeChild(a);
                            URL.revokeObjectURL(fileUrl);
                        }
                        else {
                            rtn = {
                                IsPositive: false,
                                ErrorCode: 'BadResponse',
                                ErrorSrc: 'System'
                            }
                        }
                    };
                },
                xhrFields: {
                    responseType: rspType
                },
                error: onErr || SoBiz.onNetFail
            };
            $.ajax(opt);
        },
        Connect: function (doMsg) {
            /// <summary>
            /// 创建一个长连接到实时消息服务器
            /// </summary>
            /// <params name="doMsg" type="function">接收到消息的处理方法</params>

            //根据浏览器能力使用轮询或WebSocket
            if (SoBiz.CONNECTOR.ready) {
                SoBiz.CONNECTOR.onmessage(doMsg);
            }
            else if (window.WebSocket && window.WebSocket.prototype.send) {
                JSON.merge(SoBiz.CONNECTOR, new SoBiz.wsconnector());
                SoBiz.CONNECTOR.onmessage(doMsg);

                window.addEventListener("beforeunload", function () {
                    if (SoBiz.CONNECTOR) {
                        SoBiz.CONNECTOR.dispose();
                        SoBiz.CONNECTOR = null;
                    }
                });
            }
            else {
                JSON.merge(SoBiz.CONNECTOR, new SoBiz.httpconnector());
                SoBiz.CONNECTOR.onmessage(doMsg);
            }
        },
        onNetFail: function (ev) {
            /// <summary>
            /// 通用网络错误处理
            /// </summary>
            /// <param name="ev" type="type"></param>
            if (ev.status == 401) {
                err("会话过期", "为了保护数据安全，我们需要重新验证您的身份", 5, SoBiz.LoginOut());
            }
            else if (ev.status == 403) {
                err("权限不足", "对不起，您的帐号缺少此操作所需的相应权限", 5, function () {
                    window.history.go(-1);
                });
            }
            else if (ev.status == 500) {
                //TODO:通用Debug方法发回给服务器
                SoBiz.Debug(this.url + "?" + this.data, "ServerCrash");
                err("抱歉", "服务器无法处理您的请求，我们已记录并通知管理人员，请您稍后再试");
            } else if (ev.status == 0 && ev.statusText.toLowerCase() == "timeout") {
                SoBiz.Debug(this.url + "?" + this.data, "Timeout");
                err("抱歉", "大家太热情了，服务器有点忙不过来，请您稍后再试");
            }
            else if (navigator.onLine == false) {
                err("网络故障", "无法连接到服务器，请检查网络连接情况");
            }
            else if (ev.status == 0 && ev.statusText.toLowerCase() == "error") {
                err("服务器无响应", "平台维护中，暂时无法响应您的请求");
            }
            else {
            }
        },
        User: {
            _ready: false,
            name: '',
            mphone: '',
            headimg: '#',
            mphoneStr: '-',
            ex_mphones: []
        },
        TMP: {},
        Login: function (onSuccess, onFail) {
            /// <summary>
            /// 检查当前登录状态
            /// </summary>
            /// <param name="onSuccess" type="function">标准事件回调，在登录成功后触发，返回对象包含基础用户信息</param>
            /// <param name="onFail" type="function">网络请求失败或登录失败</param>

            //判断本地登录状态
            var ut = $.Cookie("uTicket");
            if (!ut) {
                onFail ? onFail() : SoBiz.LoginOut();
                return;
            }
            else {
                var n = ut.match(/&name=(\S*?)&/);
                var m = ut.match(/&mphone=(\S*?)&/);
                var h = ut.match(/&headimg=(\S*?)$/);
                SoBiz.User.name = n && n.length > 0 ? decodeURIComponent(n[1]) : '请登录';
                SoBiz.User.mphone = m && m.length > 0 ? m[1] : "-";
                SoBiz.User.headimg = h && h.length > 0 && h[1].length > 1 ? decodeURIComponent(atob(h[1])) : "/ui/imgs/default-user-headimg.jpg";
                onSuccess && onSuccess(SoBiz.User);
                return;
            }
        },
        GetUser: function (onSuccess) {
            if (SoBiz.User._ready) {
                onSuccess && onSuccess(SoBiz.User);
                return SoBiz.User;
            }
            $$.GetJSON("/My/GetUser", null, function (rtn) {
                if (rtn.IsPositive) {
                    if (!rtn.Data.headimg) {
                        rtn.Data.headimg = '/ui/imgs/default-user-headimg.jpg';
                    };
                    rtn.Data.createtime = new Date(rtn.Data.createtime);
                    rtn.Data.mphoneStr = rtn.Data.mphone.substr(0, 3) + "****" + rtn.Data.mphone.substr(7);
                    SoBiz.User._ready = true;
                    JSON.merge(SoBiz.User, rtn.Data);
                    onSuccess && onSuccess(SoBiz.User);
                    return SoBiz.User;
                }
            });
        },
        SSOProcess: function (sites) {
            /*处理单点登录*/
            var su = $.Cookie("ssologout");
            if (su) {
                /*SSO登出其他子站*/
                $.Cookie("ssologout", "del", { expires: -1, path: '/' });
                if (sites) {
                    sites.forEach(function (u) {
                        $.ajax({
                            url: u + "/api/SoBiz/Logout",
                            crossDomain: true,
                            withCredentials: true,
                            dataType: 'jsonp'
                        });
                    });
                };
            }
            else {
                var sl = $.Cookie("ssologin");
                var ut = $.Cookie("uTicket");
                if (!sl && ut && sites) {
                    /*SSO登录其他子站*/
                    $.Cookie("ssologin", "begin", { expires: 1000, path: '/' });
                    setTimeout(function () {
                        $.getJSON("/api/SoBiz/SSOBegin", function (rtn) {
                            if (rtn.IsPositive) {
                                sites.forEach(function (u) {
                                    if (u.split("//")[1] !== window.location.host) {
                                        $.ajax({
                                            url: u + "/api/SoBiz/SSOLogin?ut=" + rtn.Data,
                                            crossDomain: true,
                                            dataType: 'jsonp',
                                            //async: false,
                                            type: 'GET'
                                        });
                                    }
                                });
                            }
                        });
                        $.Cookie("ssologin", "del", { expires: -1, path: '/' });
                    }, 1000);
                }
            }
        },
        LoginOut: function () {
            $.Cookie("ssologout", "true", { expires: 2, path: '/' });
            $.Cookie("uTicket", "loginout", { expires: -1, path: '/' });
            $$.User._ready = false;
            $$.POST("/CloudAdmin/ClearAcntCache", null, function () {
                location = "/";
            });

        },
        LoadVue: function (url, name) {
            var f = function (resolve) {
                $.ajax({
                    url: url,
                    dataType: 'html',
                    success: function (rtn) {
                        var cnt = $(rtn);
                        var id = url.hashCode();
                        var vueOpt = {
                            template: '',
                            _js: [],
                            _styles: [],
                            _id: id,
                            _jsDelay: 0
                        };

                        cnt.each(function (i) {
                            switch (this.nodeName.toLowerCase()) {
                                case "link":
                                    var oldLnk = $(document.head).children("[href='" + this.getAttribute("href") + "']");
                                    if (oldLnk.length > 0) {
                                        appendRefer(oldLnk[0], id);
                                    }
                                    else {
                                        this.setAttribute("reference", id);
                                        document.head.appendChild(this);
                                    }
                                    vueOpt._styles.push(this.getAttribute("href"));
                                    break;
                                case "script":
                                    var csrc = this.getAttribute("src")
                                    if (csrc) {
                                        var oldJS = $(document.head).children("[src='" + csrc + "']");
                                        if (oldJS.length > 0) {
                                            appendRefer(oldJS[0], id);
                                        }
                                        else {
                                            if (this.attr("async")) {
                                                vueOpt._jsDelay += 1;
                                                this.onload = function (arg) {
                                                    /*同步js文件在加载完毕后检查并回调Vue的组件构造函数*/
                                                    arg._jsDelay -= 1;
                                                    if (arg._jsDelay == 0) {
                                                        resolve(arg);
                                                    }
                                                }.bind(this, vueOpt);
                                            };
                                            $(document.head).append(this);
                                        };
                                        vueOpt._js.push(csrc);
                                    }
                                    else {
                                        JSON.merge(vueOpt, eval(this.innerText));
                                    }
                                    break;
                                case "template":
                                    vueOpt.template = this.innerHTML;
                                    break;
                                default:
                                    break;
                            }
                        });

                        /*添加mounted和destroy事件监控，处理相关样式和脚本*/
                        //var o_mounted = vueOpt.mounted;
                        if (!vueOpt.methods) {
                            vueOpt.methods = {}
                        }
                        vueOpt.methods._mounted = vueOpt.mounted || function () { };
                        vueOpt.mounted = function (ev) {
                            /*恢复此vue组件所引入的样式和脚本*/
                            vueOpt._styles.forEach(function (n) {
                                var lnk = $(document.head).children("[href='" + n + "']");
                                if (lnk.length == 0) {
                                    var s = $("<link>").attr("href", n).attr("rel", "stylesheet").attr("reference", vueOpt._id);
                                    document.head.appendChild(s[0]);
                                };
                            });
                            vueOpt._js.forEach(function (n) {
                                var lnk = $(document.head).children("[src='" + n + "']");
                                if (lnk.length == 0) {
                                    var s = $("<script>").attr("src", n).attr("reference", vueOpt._id);
                                    $(document.head).append(s);
                                };
                            });
                            this._mounted();
                            //o_mounted && o_mounted.call(this);
                        };

                        var o_beforeDestroy = vueOpt.beforeDestroyed;
                        vueOpt.beforeDestroy = function (ev) {
                            /*将此vue组件所引入的样式和脚本清除*/
                            vueOpt._styles.forEach(function (n) {
                                var lnk = $(document.head).children("[href='" + n + "']");
                                reduceRefer(lnk[0], vueOpt._id);
                            });
                            vueOpt._js.forEach(function (n) {
                                var lnk = $(document.head).children("[src='" + n + "']");
                                reduceRefer(lnk[0], vueOpt._id);
                            });
                            o_beforeDestroy && o_beforeDestroy.call(this);
                        };

                        if (vueOpt._jsDelay == 0) {
                            resolve(vueOpt);
                        }
                        cnt = null;
                    }
                });
            };

            Vue.component(name, f);
        },
        LoadView: function (elm, url) {
            /// <summary>
            /// 加载指定页面内容并替换到指定容器元素中
            /// </summary>
            /// <param name="elm" type="Dom and JQuery Object">要替换的容器元素或选择器</param>
            /// <param name="url" type="String">要加载的页面地址</param>
            elm = $(elm).first();
            if (elm.length == 0) {
                return;
            };
            var id = url.hashCode();
            var oid = elm.attr("cntid");

            if (!oid) {
                //没有旧内容，不用处理
            }
            else if (oid !== id) {
                //清理旧的DOM内容(页面动态添加到body下的元素)
                $('body').children().each(function (c) {
                    var cid = this.getAttribute("cntid");
                    if (!cid || (this.nodeName.toLowerCase() == "script" && cid == oid)) {
                        this.parentNode.removeChild(this);
                    }
                });
                //更新在head中的引用资源的被使用情况
                if (document.head.childNodes.forEach) {
                    document.head.childNodes.forEach(function (n) {
                        reduceRefer(n, oid);
                    });
                }
                else {
                    $(document.head).children().each(function (n) {
                        reduceRefer(this, oid);
                    });
                }
            }
            else {
                return;
            }

            elm.attr("cntid", id);
            elm.html("");
            elm.appendTo(elm.parent()[0]);

            elm.mask().addClass("CntLoading");
            $.ajax({
                url: url,
                dataType: 'html',
                success: function (rtn) {
                    var cnt = $(rtn);
                    var tmp = {
                        delay: 0
                    };
                    var tmpJS = [];
                    tmp.delay = cnt.filter("script").length;
                    cnt.each(function (i) {
                        switch (cnt[i].nodeName.toLowerCase()) {
                            case "link":
                                var oldLnk = $(document.head).children("[href='" + cnt[i].getAttribute("href") + "']");
                                if (oldLnk.length > 0) {
                                    appendRefer(oldLnk[0], id);
                                }
                                else {
                                    cnt[i].attr("reference", id);
                                    document.head.appendChild(cnt[i]);
                                }
                                break;
                            case "script":
                                var csrc = cnt[i].getAttribute("src");
                                if (csrc) {
                                    var oldJS = $(document.head).children("[src='" + csrc + "']");
                                    if (oldJS.length > 0) {
                                        tmp.delay -= 1;
                                        appendRefer(oldJS[0], id);
                                    }
                                    else {
                                        var script = document.createElement('script');
                                        script.type = 'text/javascript';
                                        script.src = csrc;
                                        script.setAttribute("reference", id);
                                        script.onload = function (js, arg) {
                                            arg.delay -= 1;
                                            if (arg.delay <= 0) {
                                                var bd = $(document.body);
                                                for (var i = 0; i < js.length; i++) {
                                                    bd.append(js[i]);
                                                };
                                            };
                                        }.bind(this, tmpJS, tmp);
                                        document.head.appendChild(script);
                                    }
                                }
                                else {
                                    tmp.delay -= 1;
                                    cnt[i].setAttribute("cntid", id);
                                    tmpJS.push(cnt[i]);
                                }
                                break;
                            case "title":
                                document.title = cnt[i].text;
                                break;
                            case "auth":
                                /*根据页面上的anth标签处理权限（secLv,admin,auth）,如何给错误提示页面传递所需的授权信息呢？*/
                                $(elm).load("/Error/noauth.html");
                                break;
                            case "meta":
                            case "#text":
                                break;
                            default:
                                elm[0].appendChild(cnt[i]);
                                break;
                        }
                    });
                    if (tmp.delay <= 0) {
                        var bd = $(document.body);
                        for (var i = 0; i < tmpJS.length; i++) {
                            bd.append(tmpJS[i]);
                        };
                    }
                    elm.unmask(true);
                    cnt = null;
                    tmpJS = null;
                    elm.find("._checkon").each(function () {
                        var pe = $(this);
                        if (pe.data("checker") === undefined) {
                            pe.data("checker", new LiberUI.InputChecker(elm));
                        }
                    });
                }
            });
        },
        Load: function (ev) {
            /// <summary>
            /// 基于前端路由技术的框架式加载技术
            /// </summary>
            var path;
            var route;
            if (RES.RouteTable) {
                /*检测路由，重写浏览器地址栏信息*/
                var cpath = window.location.pathname.toLowerCase();
                var chash = window.location.hash.toLowerCase();
                for (var r in RES.RouteTable) {
                    if (cpath.indexOf(r) > -1) {
                        path = cpath;
                        //针对IE有时pathname会没有前面的斜杠进行处理
                        if (path.substr(0, 1) !== '/') {
                            path = '/' + path;
                        };
                        route = RES.RouteTable[r];
                        break;
                    }
                    else if (chash.indexOf(r) > -1) {
                        path = chash.substring(1);
                        route = RES.RouteTable[r];
                        if (window.location.search) {
                            path = path + window.location.search.substring(1);
                        }
                       
                        break;
                    }
                    else {
                    }
                }
            };

            if (!path || !route) {
                window.location = "/Error/404.html";
                return;
            };

            ev && ev.preventDefault() && ev.stopPropagation();

            /*切换模板，重新加载所有页面*/
            if (route.template && SoBiz.Page && SoBiz.Page.template !== route.template) {
                if (SoBiz.CONNECTOR) {
                    SoBiz.CONNECTOR.dispose();
                };
                window.location = route.template + "#" + path;
                window.localStorage.removeItem("_page");
                return;
            };

            /*初始化一个待加载内容列表*/
            var tmp = [];

            //模板初始化
            if (!SoBiz.Page.TMP) {
                /*完全重新加载*/
                $(document.body).undelegate("a[href!='#'][exp!='true']", 'click');
                /*拦截所有a链接跳转和地址栏变动行为，改为模板加载*/
                $(document.body).delegate("a[href!='#'][exp!='true']", "click", function (ev) {
                    var lnk = this.getAttribute("href");
                    if (!lnk) {
                        return false;
                    }
                    lnk = lnk.toLowerCase();
                    if (lnk.indexOf(".html") == -1) {
                        window.history.pushState ? window.history.pushState(null, "", lnk) : window.location.hash = lnk;
                        SoBiz.Load(ev);
                        return false;
                    };
                });

                if (!window.onpopstate) {
                    window.onpopstate = SoBiz.Load;
                    window.onhashchange = SoBiz.Load;
                }

                window.history.replaceState(null, "", path);
                SoBiz.Page.template = r.template || '/ui/normal.html';
                SoBiz.Page.Section = {};
                SoBiz.Page.TMP = {};
            };

            window.postMessage("locationChanged", "/");

            $("body").find("[section]").each(function (s) {
                SoBiz.Page.Section[this.getAttribute("section")] = { domid: "#" + this.ID(), url: '' };
            });

            //处理模板公共区域
            for (var s in route.section) {
                if (SoBiz.Page.Section[s] && SoBiz.Page.Section[s].url != route.section[s]) {
                    tmp.push({
                        elm: SoBiz.Page.Section[s].domid,
                        url: route.section[s]
                    });
                }
            };

            //处理当前页面的个性化区域
            for (var m in route.map) {
                if (0==path.indexOf(m) && m.indexOf('*') == -1) {
                    var croute = route.map[m];
                    for (var s in croute) {
                        if (SoBiz.Page.Section[s] && SoBiz.Page.Section[s].url != croute[s]) {
                            tmp.push({
                                elm: SoBiz.Page.Section[s].domid,
                                url: croute[s]
                            });
                        }
                    }
                    break;
                }
            };

            //执行动态加载
            for (var i = 0; i < tmp.length; i++) {
                SoBiz.LoadView(tmp[i].elm, tmp[i].url);
            };
            return SoBiz.Page;
        },
        Page: {
            template: '/ui/normal.html',
            Section: {}
        },
        _eventHandlers: {},

        on: function (event, fnCallback) {
            /// <summary>
            /// 绑定全局状态事件
            /// </summary>
            /// <param name="event" type="type"></param>
            /// <param name="fnCallback" type="type"></param>
            if (!SoBiz._eventHandlers[event]) {
                SoBiz._eventHandlers[event] = [];
            }
            SoBiz._eventHandlers[event].push(fnCallback);
            return SoBiz;
        },

        off: function (event, fnCallback) {
            /// <summary>
            /// 解除全局状态事件绑定
            /// </summary>
            /// <param name="event" type="type">要解除的事件类型</param>
            /// <param name="fnCallback" type="type">要解除的回调方法，不传则解除所有已绑定的回调</param>

            if (SoBiz._eventHandlers[event]) {
                if (fnCallback) {
                    for (var h in SoBiz._eventHandlers.event) {
                        if (SoBiz._eventHandlers.event[h] === fnCallback) {
                            SoBiz._eventHandlers.event.splice(h, 1);
                            break;
                        }
                    }
                }
                else {
                    SoBiz._eventHandlers[event] = [];
                    delete SoBiz._eventHandlers[event];
                }
            }
            return SoBiz;
        },

        trigger: function (event, data) {
            /// <summary>
            /// 发出全局事件通知
            /// </summary>
            /// <param name="event" type="type">事件类型</param>
            /// <param name="data" type="type">事件参数</param>
            if (SoBiz._eventHandlers[event]) {
                SoBiz._eventHandlers[event].forEach(function (h) {
                    try {
                        h.call(SoBiz, data);
                    }
                    catch (ex) {
                        SoBiz.Debug(window.location.href, "ExceptionOnEvent:" + event);
                    }
                });
            }
            return SoBiz;
        },

        wsconnector: function () {
            var msgCallbacks = [];
            var ws;
            var clntid;
            var svr = (RES.IMSSL ? "wss://" : "ws://") + RES.IMSvr + "/ws";
            var msgCache = [];
            SoBiz.SessionID(function (c) {
                clntid = c;
                ws = new WebSocket(svr + "?clntid=" + clntid);
                ws.onclose = function (ev) {
                };
                ws.onerror = function (er) {
                    console.log("wsconnector err", er);
                };
                ws.onopen = function (ep) {
                    console.log("wsconnector ready", ep);
                    //检查是否存在待发送的消息
                };
                ws.onmessage = function (m) {
                    msgCallbacks.forEach(function (f) {
                        f.call(this, JSON.parse(m.data));
                    });
                };
            });

            this.onmessage = function (fnCallback) {
                msgCallbacks.push(fnCallback);
                return this;
            };
            this.offmessage = function (fnCallback) {
                msgCallbacks.removeOn(fnCallback);
                return this;
            };
            this.sendmessage = function (msg) {
                if (ws.readyState == 1) {
                    //已连接，直接发送
                    ws.send(msg);
                }
                else {
                    //TODO:重新连接，缓存待发送消息
                    msgCache.push(msg);
                    ws = new WebSocket(svr + "?clntid=" + clntid);
                }
                return this;
            };
            this.dispose = function () {
                ws.close();
                ws = null;
                this.ready = false;
                return null;
            };
            this.ready = true;
            return this;
        },

        httpconnector: function () {
            var clntid;
            var msgCallbacks = [];
            var lstn = function () {
                if (msgCallbacks.length > 0) {
                    SoBiz.SessionID(function (clnt){
                        this.clntid = clnt;
                        $.getJSON((RES.IMSSL ? "https://" : "http://") + RES.IMSvr + "/im" + "?clntid=" + clntid, function (rtn) {
                            //TODO:处理拉取到的消息,间隔轮询
                            setTimeout(this.lstn, 1000);
                        });
                    });
                }
            }.bind(this);

            this.onmessage = function (fnCallback) {
                msgCallbacks.push(fnCallback);
                lstn();
                return this;
            };
            this.dispose = function () {
                this.ready = false;
                return null;
            };
            this.ready = true;
            lstn();
            return this;
        },

        CONNECTOR: {
            ready: false,
            dispose: function () { }
        },

        taskmng: function (reqs, tm) {
            var jobs = [];
            var fnThen = null;
            var ender = null;
            var chker = null;
            var isCompleted = false;
            var timeout = 30000;
            var start = new Date();

            var monit = function () {
                if (new Date() - start > timeout) {
                    clearInterval(chker);
                    jobs = [];
                    return;
                }
                else {
                    for (var i = 0; i < jobs.length; i++) {
                        if (jobs[i].readyState == 4) {
                            clearInterval(chker);
                            jobs = [];
                            isCompleted = true;
                            fnThen && fnThen.call();
                            return;
                        }
                    }
                }

            };

            this.Do = function (job) {
                jobs.push(job);
                if (!chker && !isCompleted) {
                    chker = setInterval(monit, 50);
                }
                return this;
            };

            this.Then = function (fn, tm) {
                if (isCompleted) {
                    fn && fn.call();
                }
                else {
                    fnThen = fn;
                    timeout = tm;
                }

                return this;
            };

            return this;
        },

        Debug: function (src, err) {
            /// <summary>
            /// TODO:记录前端错误以供后期调试分析
            /// </summary>
            /// <param name="src" type="String">请求地址和参数</param>
            /// <param name="err" type="String">错误描述</param>
        },
        CheckAll: function ($e) {
            if (!$e) {
                $e = $("body");
            }
            $e.find("data-checker");
        }
    };

    window.$$ = window.SoBiz;

    Object.freeze(window.SoBiz);
    Object.defineProperty(window, 'SoBiz', {
        writable: false
    });
}

//全局页面基础支持
$(function () {
    //异步页面部件加载
    setTimeout(function () {
        $("body").find(".Tabs").each(function (t) {
            var tab = $(this).children(".active").first();
            if (tab.length == 0) {
                tab = $(this).children("span").first();
            }
            if (tab.length > 0 && $(this).children(".tab-hover").length == 0) {
                var hovr = $("<div class='tab-hover'>").insertAfter(tab);
                hovr.width(tab.outerWidth())
                    .css("left", tab.offset().left - tab.offsetParent().offset().left);
            }
        });

        $('body').find("[content-src]").each(function (e) {
            var cnt = this.getAttribute("content-src");
            var rp = this.getAttribute("replace");
            var refDom = $(this);
            if (!rp) {
                $(this).load(cnt);
            }
            else {
                var refDom = $(this);
                $.ajax({
                    url: cnt,
                    dataType: "html",
                    success: function (rtn) {
                        $(rtn).insertBefore(refDom);
                        refDom.remove();
                    }
                });
            }
        });
    }, 200);

    $("body").delegate(".Tabs>span", "mouseenter", function (ev) {
        var tab = $(this);
        var hovr = tab.siblings(".tab-hover");
        if (hovr.length == 0) {
            hovr = $("<div class='tab-hover'>").insertAfter(tab);
        }
        hovr.width(tab.outerWidth())
            .css("left", tab.offset().left - tab.offsetParent().offset().left);
    }).on("mouseleave", ".Tabs", function (ev) {
        var hovr = $(this).children(".tab-hover");
        var tab = $(this).children(".active");

        if (hovr.length == 0) {
            hovr = $("<div class='tab-hover'>").appendTo(this);
        }
        if (tab.length > 0) {
            hovr.width(tab.outerWidth())
                .css("left", tab.offset().left - tab.offsetParent().offset().left);
        }
    });

    $("body").on("DOMSubtreeModified", function (e) {
        $("body").find("._checkon").each(function () {
            var elm = $(this);
            if (!elm.data("checker")) {
                elm.data("checker", new LiberUI.InputChecker(elm));
            }
        });
    });
    SoBiz.SSOProcess(RES.SSOUrl);
});

function reduceRefer(n, oid) {
    var nn = n.nodeName.toLowerCase();
    if (nn == 'script' || nn == 'link') {
        var refsAttr = n.getAttribute("reference");
        var refs = refsAttr !== null ? refsAttr.replace(/oid/g, ''): 'raw';
        if (refs.trim().length == 0) {
            console.log('try remove');
            document.head.removeChild(n);
        }
        else {
            n.setAttribute("reference", refs);
        }
    }
}

function appendRefer(n, id) {
    var refAttr = n.getAttribute("reference");
    if (!refAttr || refAttr.indexOf(id) == -1) {
        n.setAttribute("reference", refAttr + " " + id);
    }
}
